/*
 * Copyright (c) 2003-2004 by Woehrmann Softwareentwicklung
 *
 * Woehrmann Softwareentwicklung (hereinafter referred to as "Developer")
 * grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that Licensee does not utilize the software in a manner
 * which is disparaging to the Developer.
 *
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE DEVELOPER SHALL NOT BE LIABLE
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL THE DEVELOPER
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY
 * TO USE SOFTWARE, EVEN IF THE DEVELOPER HAS BEEN ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGES.
 *
 */

package gui;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

/**
 * Superclass of source code generated GUI components in this environment.
 *
 * <p>Copyright (c) 2003-2004 by Woehrmann Softwareentwicklung</p>
 *
 * @author Hermann Woehrmann
 * @version 3.05 14.05.2003
 */
 @SuppressWarnings("unchecked")
public class GUIObject
{
private Hashtable components;
  private Hashtable buttonGroups;

/**
 * Creates a new <code>GUIObject</code>
 */
  public GUIObject()
  { components = new Hashtable();
    buttonGroups = new Hashtable();
  }

/**
 * Gets a <code>Component</code> contained in this <code>GUIObject</code>.
 *
 * @param componentName as the name of the wanted <code>Component</code>.
 * @return <code>Component</code> or null if no component is found.
 */
  public Component getComponent(String componentName)
  { return (Component)components.get(componentName);
  }

/**
 * Adds a <code>Component</code> to the list of this contained components.
 *
 * @param component as to be added <code>Component</code> to the list of components.
 * @return this <code>GUIObject</code>.
 */
  protected GUIObject add(Component component)
  { components.put(component.getName(), component);
    return this;
  }

/*****************************************************************************/
// Management of Button Groups ...
/*****************************************************************************/

  private void addButtonGroup(String groupName, ButtonGroup group)
  { buttonGroups.put(groupName, group);
  }

/**
 * Gets a <code>ButtonGroup</code> appropriate the given groupName.
 * If no <code>ButtonGroup</code> with this groupName is present a new one will be created.
 *
 * @param groupName as name of the <code>ButtonGroup</code>.
 * @return <code>ButtonGroup</code> for groupName.
 */
  public ButtonGroup getButtonGroup(String groupName)
  { ButtonGroup group = (ButtonGroup)buttonGroups.get(groupName);
    if (group == null)
    { group = new ButtonGroup();
      addButtonGroup(groupName, group);
    }
    return group;
  }

/*****************************************************************************/
// Set preferred Component size dependent on Container size
/*****************************************************************************/

/**
 * Calculates a components dimension depending on its preferred size and the
 * size of its parent container.
 *
 * @param preferredDefault as the primary preferred size.
 * @param container as the parent container to be considered.
 * @param sdivX as measurement of width fraction.
 * @param sdivY as measurement of height fraction.
 * @param smulX as measurement of width multiple.
 * @param smulY as measurement of height multiple.
 * @param splusX as measurement of width additional pixels.
 * @param splusY as measurement of height additional pixels.
 *
 * @return new <code>Dimension</code> as preferred size.
 */
  public static Dimension getPreferredSize(
    Dimension preferredDefault, Container container,
    String sdivX,  String sdivY,  // preferred DivX,  DivY
    String smulX,  String smulY,  // preferred MulX,  MulY
    String splusX, String splusY) // preferred PlusX, PlusY
  {
    Insets insets = container.getInsets();
    int hgap = 0, vgap = 0;
    if (FlowLayout.class.isInstance(container.getLayout()))
    { FlowLayout lm = (FlowLayout)container.getLayout();
      hgap = lm.getHgap();
      vgap = lm.getVgap();
    }
    if (BorderLayout.class.isInstance(container.getLayout()))
    { BorderLayout lm = (BorderLayout)container.getLayout();
      hgap = lm.getHgap();
      vgap = lm.getVgap();
    }
    if (GridLayout.class.isInstance(container.getLayout()))
    { GridLayout lm = (GridLayout)container.getLayout();
      hgap = lm.getHgap();
      vgap = lm.getVgap();
    }
    int dimX = preferredDefault.width;
    int dimY = preferredDefault.height;
    try
    { int mulX = (smulX == null) ? 1 : Integer.parseInt(smulX);
      if (sdivX != null)
      { int divX = Integer.parseInt(sdivX);
        int nettoWidth = container.getWidth() - insets.left - insets.right;
        if (hgap != 0) nettoWidth = nettoWidth - (hgap * divX / mulX);
        dimX = nettoWidth * mulX / divX;
      }
      if (splusX != null) dimX = dimX + Integer.parseInt(splusX);
      int mulY = (smulY == null) ? 1 : Integer.parseInt(smulY);
      if (sdivY != null)
      { int divY = Integer.parseInt(sdivY);
        int nettoHeight = container.getHeight() - insets.top - insets.bottom;
        if (vgap != 0) nettoHeight = nettoHeight - (vgap * divY / mulY);
        dimY = nettoHeight * mulY / divY;
      }
      if (splusY != null) dimY = dimY + Integer.parseInt(splusY);
    }
    catch (Exception e)
    { return preferredDefault;
    }
    return new Dimension(dimX, dimY);
  }

/*****************************************************************************/
// Load an Image from Classpath
/*****************************************************************************/

/**
 * Defines the defaultToolkit as <code>Toolkit.getDefaultToolkit()</code>.
 */
  public static Toolkit defaultToolkit = Toolkit.getDefaultToolkit();

  private static Hashtable images = new Hashtable();

/**
 * Gets an <code>Image</code> from CLASSPATH appropriate the given imageName.
 * Internally caches the <code>Image</code>.
 *
 * @param imageName as name of the <code>Image</code> to be loaded.
 * @return <code>Image</code> for imageName.
 * @throws RuntimeException if <code>Image</code> is not loadable.
 */
  public static Image getImageResource(String imageName)
  { Image image = (Image)images.get(imageName);
    if (image != null) return image;
    try
    { InputStream in = GUIObject.class.getResourceAsStream(imageName);
      if (in != null)
      { ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int ch;
        while((ch = in.read()) != -1) buffer.write(ch);
        image = defaultToolkit.createImage(buffer.toByteArray());
        if (image != null)
        { images.put(imageName, image);
          return image;
        }
      }
    }
    catch (Exception ex) { throw new RuntimeException(ex); }
    throw new RuntimeException("ImageResource not found (Image:" + imageName);
  }

/*****************************************************************************/
// Load file-content from Classpath
/*****************************************************************************/

/**
 * Gets the content of a text file reachable via CLASSPATH.
 *
 * @param fileName as name of the <code>File</code>.
 * @return <code>String</code> as content of the <code>File</code>.
 * @throws RuntimeException if <code>File</code> is not found.
 */
  public static String getFileResource(String fileName)
  { try
    { InputStream in = GUIObject.class.getResourceAsStream(fileName);
      BufferedReader reader = new BufferedReader(new InputStreamReader(in));
      StringBuffer sb = new StringBuffer();
      String line;
      while((line = reader.readLine()) != null)
      { sb.append(line).append("\n");
      }
      in.close();
      return sb.toString();
    }
    catch (Exception e)
    { throw new RuntimeException("FileResource not found (File:" + fileName);
    }
  }

/*****************************************************************************/
// Create a PopupMenuListener
/*****************************************************************************/

/**
 * Embedded class for handling of <code>JPopupMenu</code>s.
 */
  public static class PopupMenuController extends MouseAdapter
  { JPopupMenu popupMenu;
    Component  popupAble;
    int        addX, addY;

/**
 * Creates a new <code>PopupMenuController</code>.
 * Popup menus will be popped up with their upper left corner under the current mouse position.
 *
 * @param p as <code>JPopupMenu</code> to be handled.
 * @param c as <code>JPopupMenu</code>able <code>Component</code>.
 * @param ax as X-adjustment of popup position.
 * @param ay as Y-adjustment of popup position.
 */
    public PopupMenuController(JPopupMenu p, Component c, int ax, int ay)
    { popupMenu = p;
      popupAble = c;
      addX = ax;
      addY = ay;
      popupAble.addMouseListener(this);
    }

/**
 * Creates a new <code>PopupMenuController</code>.
 * Popup menus will be popped up with their upper left corner under the current mouse position.
 *
 * @param p as <code>JPopupMenu</code> to be handled.
 * @param c as <code>JPopupMenu</code>able <code>Component</code>.
 */
    public PopupMenuController(JPopupMenu p, Component c)
    { this(p, c, 0, 0);
    }

    public void mousePressed(MouseEvent e)
    { showPopupMenu(e);
    }

    public void mouseClicked(MouseEvent e)
    { showPopupMenu(e);
    }

    public void mouseReleased(MouseEvent e)
    { showPopupMenu(e);
    }

    private void showPopupMenu(MouseEvent e)
    { if (e.isPopupTrigger())
      { popupMenu.show(popupAble, e.getX() + addX, e.getY() + addY);
      }
    }
  }
}
